// Array

// Array.prototype.reduce
if(!Array.prototype.reduce) {
  Array.prototype.reduce = function(reducer, initialValue) {
    const array = Array.prototype.slice.apply(this);
    if(typeof reducer !== 'function') throw new TypeError(`${typeof reducer !== 'object' ? reducer : Object.prototype.toString.apply(reducer)} is not a function`);
    const hasInitial = arguments.length >= 2;
    const length = array.length;
    if(length == 0) {
      if(!hasInitial) throw new TypeError('Reduce of empty array with no initial value');
      return initialValue;
    }
    if(length == 1 && !hasInitial) return array[0];
    let index = 0;
    if(!hasInitial) {
      initialValue = array[index];
      index += 1;
    }
    for(let i = index; i < length; i++) {
      initialValue = reducer(initialValue, array[i], i, array);
    }
    return initialValue;
  }
}

// Array.prototype.reduceRight
if(!Array.prototype.reduceRight) {
  Array.prototype.reduceRight = function(reducer, initialValue) {
    const array = Array.prototype.slice.apply(this);
    if(typeof reducer !== 'function') throw new TypeError(`${typeof reducer !== 'object' ? reducer : Object.prototype.toString.apply(reducer)} is not a function`);
    const hasInitial = arguments.length >= 2;
    const length = array.length;
    if(length == 0) {
      if(!hasInitial) throw new TypeError('Reduce of empty array with no initial value');
      return initialValue;
    }
    if(length == 1 && !hasInitial) return array[0];
    let index = length - 1;
    if(!hasInitial) {
      initialValue = array[index];
      index -= 1;
    }
    for(let i = index; i >= 0; i--) {
      initialValue = reducer(initialValue, array[i], i, array);
    }
    return initialValue;
  }
}